package nginx

import (
	"flag"
	"fmt"
	"net/http"
	"net/http/httputil"
	"os"
	"runtime"
	"strconv"
	"strings"
	"time"
)

type Index struct {
	Port         int    `json:"port"`
	Root         string `json:"root"`
	Index        string `json:"index"`
	ProxyPrefix  string `json:"proxy_prefix"`
	ProxyAddress string `json:"proxy_address"`
}

func (index *Index) InitStartupParameters() *Index {
	flag.StringVar(&index.Root, "root", "./", "项目路径")
	flag.StringVar(&index.Index, "index", "/index.html", "默认首页")
	flag.IntVar(&index.Port, "port", 8080, "服务端口")
	flag.StringVar(&index.ProxyPrefix, "proxy_prefix", "", "代理路径")
	flag.StringVar(&index.ProxyAddress, "proxy_address", "", "转发路径")

	fmt.Printf("=== 启动参数：%v ===\n", index)

	return index
}

func (index *Index) isProxyUri(uri string) bool {
	return len(index.ProxyPrefix) > 0 && len(index.ProxyAddress) > 0 && strings.HasPrefix(uri, index.ProxyPrefix)
}

func (index *Index) ProxyHTTP(writer http.ResponseWriter, request *http.Request) {
	director := func(req *http.Request) {
		path := strings.Replace(request.RequestURI, index.ProxyPrefix, "", 1)
		url, err := req.URL.Parse(index.ProxyAddress + path)
		if err != nil {
			fmt.Printf("解析ProxyAddress错误请输入正确的HTTP地址 %v\n%v\n", index.ProxyAddress, err)
		} else {
			req.URL = url
		}
	}
	proxy := &httputil.ReverseProxy{Director: director}
	proxy.ServeHTTP(writer, request)
}

func (index *Index) ServeHTTP(writer http.ResponseWriter, request *http.Request) {
	uri := request.RequestURI
	if len(uri) <= 0 || uri == "/" {
		uri = index.Index
	}
	if index.isProxyUri(uri) {
		index.ProxyHTTP(writer, request) // 代理模式
	} else {
		filePath := index.getFilePath(uri)
		stat, err := os.Stat(filePath)
		if err != nil {
			index.response404Error(writer, request)
			return
		}
		bytes, e := os.ReadFile(filePath)
		if e != nil {
			index.response404Error(writer, request)
			return
		}
		writer.WriteHeader(200)
		writer.Header().Set("Content-Type", http.DetectContentType(bytes))
		writer.Header().Set("Content-Disposition", fmt.Sprintf("inline; filename=\"%s\"", stat.Name()))
		writer.Header().Set("Content-Length", strconv.FormatInt(stat.Size(), 10))
		size, we := writer.Write(bytes)
		if we != nil {
			fmt.Printf("写响应错误：%v \t %v \t %v \n", filePath, size, we)
		}
		fmt.Printf("%v \t %v \t %v \t %v \n", time.Now().Format("2006-01-02 15:04:05"), 200, uri, filePath)
	}
}

func (index *Index) getFilePath(uri string) string {
	pathPrefix := index.Root
	if pathPrefix == "./" || len(pathPrefix) <= 0 {
		getcwd, err := os.Getwd()
		if err != nil {
			panic(err) // 获取路径错误直接终止程序
		}
		pathPrefix = getcwd
	}
	fullPath := pathPrefix + uri
	if strings.HasPrefix(runtime.GOOS, "windows") {
		fullPath = strings.Replace(fullPath, "/", "\\", -1)
	} else {
		fullPath = strings.Replace(fullPath, "\\", "/", -1)
	}
	return fullPath
}

func (index *Index) response404Error(writer http.ResponseWriter, request *http.Request) {
	writer.WriteHeader(404)
	writer.Header().Set("Content-Type", "text/plain; charset=utf-8")
	size, we := writer.Write([]byte("404: not found"))
	if we != nil {
		fmt.Printf("写响应错误：%v \t %v \n", size, we)
	}
	fmt.Printf("%v \t %v \t %v \n", time.Now().Format("2006-01-02 15:04:05"), 404, request.RequestURI)
}
